www.gusucode.com > VC++ 增强版CListCtrl控件(可日历选择、下拉列表、编辑等)-源码 > VC++ 增强版CListCtrl控件(可日历选择、下拉列表、编辑等)-源码程序/code/HeaderCtrlExt.cpp
// HeaderCtrlExt.cpp : implementation of the CHeaderCtrlExt class // Downloload by http://www.NewXing.com #include "stdafx.h" #include "HeaderCtrlExt.h" #include <atlbase.h> #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif UINT WM_HDN_ENDDRAG = ::RegisterWindowMessage("{8548F4AE-4A04-4c1e-9D0C-51CAEBEEA587}"); ///////////////////////////////////////////////////////////////////////////// // CHeaderCtrlExt IMPLEMENT_DYNAMIC(CHeaderCtrlExt, CHeaderCtrl) CHeaderCtrlExt::CHeaderCtrlExt() :m_nItemWidth(0) ,m_nDraggingItem(-1) ,m_bDragFullWindow(FALSE) { } CHeaderCtrlExt::~CHeaderCtrlExt() { } BEGIN_MESSAGE_MAP(CHeaderCtrlExt, CHeaderCtrl) //{{AFX_MSG_MAP(CListCtrlExt) ON_WM_DESTROY() ON_WM_SETCURSOR() ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONDBLCLK() ON_WM_CAPTURECHANGED() //}}AFX_MSG_MAP ON_REGISTERED_MESSAGE(WM_HDN_ENDDRAG, OnHdnEndDrag) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CHeaderCtrlExt message handlers DWORD_PTR CHeaderCtrlExt::GetItemData(int nIndex) { HDITEM hdi; hdi.mask = HDI_LPARAM; if(GetItem(nIndex, &hdi))return (DWORD_PTR)hdi.lParam; return NULL; } BOOL CHeaderCtrlExt::SetItemData(int nIndex, DWORD_PTR dwData) { HDITEM hdi; hdi.mask = HDI_LPARAM; hdi.lParam = (LPARAM)dwData; return SetItem(nIndex, &hdi); } int CHeaderCtrlExt::IndexToOrder(int nIndex) { int nOrder = -1; const int nCount = GetItemCount(); if(nCount > 0) { int* piColOrder = new int[nCount]; ASSERT(piColOrder); GetOrderArray(piColOrder, nCount); for(int i = 0;i < nCount;++i) { if(piColOrder[i] == nIndex) { nOrder = i; break; } } delete []piColOrder; } return nOrder; } void CHeaderCtrlExt::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default HDHITTESTINFO ht; ht.pt = point; int nIndex = (int)SendMessage(HDM_HITTEST, 0, (LPARAM)&ht); if(nIndex >= 0) { if(ht.flags == HHT_ONDIVIDER) { ReleaseCapture(); m_nDraggingItem = nIndex; } else if (ht.flags == HHT_ONDIVOPEN) { ReleaseCapture(); m_nDraggingItem = FindVisibleItem(nIndex); } if(m_nDraggingItem >= 0) { m_ptDragStart = point; BeginDragDivider(); return; } } CHeaderCtrl::OnLButtonDown(nFlags, point); } void CHeaderCtrlExt::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if(m_nDraggingItem >= 0) { int dx = point.x - m_ptDragStart.x; int cxy = max(0, m_nItemWidth + dx); if(m_bDragFullWindow)SetItemWidth(m_nDraggingItem, cxy); else { DrawDragDivider(); m_ptDragMove = point; DrawDragDivider(); } return; } CHeaderCtrl::OnMouseMove(nFlags, point); } void CHeaderCtrlExt::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default if(m_nDraggingItem >= 0) { m_ptDragEnd = point; EndDragDivider(TRUE); return; } CHeaderCtrl::OnLButtonUp(nFlags, point); } BOOL CHeaderCtrlExt::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { // TODO: Add your message handler code here and/or call default // return CHeaderCtrl::OnSetCursor(pWnd, nHitTest, message); HCURSOR hCursor = NULL; HDHITTESTINFO ht; ::GetCursorPos(&ht.pt); ScreenToClient(&ht.pt); int nIndex = (int)SendMessage(HDM_HITTEST, 0, (LPARAM)&ht); if(nIndex >= 0) { if(ht.flags == HHT_ONDIVIDER) { // hCursor = AfxGetApp()->LoadCursor(IDC_HEADER_SIZE); hCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE); ASSERT(hCursor != NULL); } else if(ht.flags == HHT_ONDIVOPEN) { int nItem = FindVisibleItem(nIndex); if(nItem >= 0) { if(GetItemWidth(nItem) > 0) { // hCursor = AfxGetApp()->LoadCursor(IDC_HEADER_SIZE); hCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE); } else { // hCursor = AfxGetApp()->LoadCursor(IDC_HEADER_OPEN); hCursor = AfxGetApp()->LoadStandardCursor(IDC_SIZEWE); } } } } if(hCursor == NULL)hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW); ::SetCursor(hCursor); return TRUE; } void CHeaderCtrlExt::OnLButtonDblClk(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default HDHITTESTINFO ht; ::GetCursorPos(&ht.pt); ScreenToClient(&ht.pt); int nIndex = (int)SendMessage(HDM_HITTEST, 0, (LPARAM)&ht); if(nIndex >= 0) { if(ht.flags == HHT_ONDIVOPEN) { int nItem = FindVisibleItem(nIndex); if(nItem >= 0) { if(GetItemWidth(nItem) > 0) { NMHEADER nmh; nmh.hdr.code = HDN_DIVIDERDBLCLICK; nmh.hdr.hwndFrom = m_hWnd; nmh.hdr.idFrom = GetDlgCtrlID(); nmh.iButton = 0; nmh.iItem = nItem; nmh.pitem = NULL; // not used for HDN_DIVIDERDBLCLICK GetParent()->SendMessage(WM_NOTIFY, (WPARAM)nmh.hdr.idFrom, (LPARAM)&nmh); } } } } CHeaderCtrl::OnLButtonDblClk(nFlags, point); } LRESULT CHeaderCtrlExt::OnHdnEndDrag(WPARAM wParam, LPARAM lParam) { int nCount = GetItemCount(); int* piArray = new int[nCount]; GetOrderArray(piArray, nCount); SetOrderArray(nCount, piArray); delete []piArray; return 1; } void CHeaderCtrlExt::OnDestroy() { CHeaderCtrl::OnDestroy(); // TODO: Add your message handler code here for(int i = 0;i < GetItemCount();++i) { delete (CItemData*)GetItemData(i); SetItemData(i, NULL); } } void CHeaderCtrlExt::OnCaptureChanged(CWnd* pWnd) { // TODO: Add your message handler code here if(pWnd != this && m_nDraggingItem >= 0)EndDragDivider(FALSE); CHeaderCtrl::OnCaptureChanged(pWnd); } BOOL CHeaderCtrlExt::SetItemWidth(int nIndex, int nWidth) { HDITEM hdi; memset(&hdi, 0, sizeof(hdi)); hdi.mask = HDI_WIDTH; hdi.cxy = nWidth; return SetItem(nIndex, &hdi); } int CHeaderCtrlExt::GetItemWidth(int nIndex) { HDITEM hdi; memset(&hdi, 0, sizeof(hdi)); hdi.mask = HDI_WIDTH; if(GetItem(nIndex, &hdi))return hdi.cxy; return 0; } BOOL CHeaderCtrlExt::GetWidthArray(int* piArray, int nCount) { HDITEM hdi; memset(&hdi, 0, sizeof(hdi)); hdi.mask = HDI_WIDTH; for(int i = 0;i < nCount;++i) { if(! GetItem(i, &hdi))return FALSE; piArray[i] = hdi.cxy; } return TRUE; } BOOL CHeaderCtrlExt::SetWidthArray(int nCount, int* piArray) { HDITEM hdi; memset(&hdi, 0, sizeof(hdi)); hdi.mask = HDI_WIDTH; for(int i = 0;i < nCount;++i) { hdi.cxy = piArray[i]; if(! SetItem(i, &hdi))return FALSE; } return TRUE; } BOOL CHeaderCtrlExt::GetVisibleArray(int* piArray, int nCount) { for(int i = 0;i < nCount;++i)piArray[i] = GetVisible(i); return TRUE; } BOOL CHeaderCtrlExt::SetVisibleArray(int nCount, int* piArray) { for(int i = 0;i < nCount;++i)SetVisible(i, piArray[i]); return TRUE; } BOOL CHeaderCtrlExt::SetOrderArray(int nCount, LPINT piArray) { // move all hidden items to the end int* piArrayNew = new int[nCount]; int* p1 = piArrayNew; int* p2 = piArrayNew + (nCount - 1); for(int i = 0;i < nCount;++i) { int nIndex = piArray[i]; if(GetVisible(nIndex))*p1++ = nIndex; else *p2-- = nIndex; } BOOL bReturn = CHeaderCtrl::SetOrderArray(nCount, piArrayNew); delete []piArrayNew; GetParent()->Invalidate(); return bReturn; } BOOL CHeaderCtrlExt::GetVisible(int nIndex) { CItemData* pData = (CItemData*)GetItemData(nIndex); if(pData)return pData->m_bVisible; else return FALSE; } void CHeaderCtrlExt::SetVisible(int nIndex, BOOL bVisible) { CItemData* pData = (CItemData*)GetItemData(nIndex); if(! pData)return; if(pData->m_bVisible != bVisible) { pData->m_bVisible = bVisible; // get total items int nCount = GetItemCount(); // get current item's order int nOrder = IndexToOrder(nIndex); int* piCols = new int[nCount]; ASSERT(piCols); GetOrderArray(piCols, nCount); if(bVisible) { // restore item width ResetItemWidth(nIndex); // move the item to the original position int nTarget; int nVisible = GetVisibleItemCount(); if(nIndex > nVisible - 1)nTarget = nVisible - 1; else nTarget = nIndex; ASSERT(nTarget <= nOrder); for(int i = nOrder;i > nTarget;--i)piCols[i] = piCols[i - 1]; piCols[nTarget] = nIndex; } else { // hide item SetItemWidth(nIndex, 0); } SetOrderArray(nCount, piCols); delete []piCols; } } int CHeaderCtrlExt::FindVisibleItem(int nIndex) { if(GetVisible(nIndex))return nIndex; int nOrder = IndexToOrder(nIndex); while(nOrder > 0) { nIndex = OrderToIndex(--nOrder); if(GetVisible(nIndex))return nIndex; } return -1; } int CHeaderCtrlExt::GetVisibleItemCount() { int nVisible = 0; int nCount = GetItemCount(); for(int i = 0;i < nCount;++i) if(GetVisible(i))nVisible++; return nVisible; } int CHeaderCtrlExt::GetRemovableItemCount() { int nRemovable = 0; int nCount = GetItemCount(); for(int i = 0;i < nCount;++i) { if(GetRemovable(i))nRemovable++; } return nRemovable; } BOOL CHeaderCtrlExt::GetRemovable(int nIndex) { CItemData* pData = (CItemData*)GetItemData(nIndex); if(pData)return pData->m_bRemovable; else return FALSE; } void CHeaderCtrlExt::SetRemovable(int nIndex, BOOL bRemovable) { CItemData* pData = (CItemData*)GetItemData(nIndex); if(pData)pData->m_bRemovable = bRemovable; } void CHeaderCtrlExt::BeginDragDivider() { SetCapture(); m_nItemWidth = GetItemWidth(m_nDraggingItem); // check if dragging full window is enabled ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &m_bDragFullWindow, 0); m_ptDragMove = m_ptDragStart; if(! m_bDragFullWindow)DrawDragDivider(); } void CHeaderCtrlExt::EndDragDivider(BOOL bSubmit) { if(! m_bDragFullWindow)DrawDragDivider(); if(bSubmit) { if(! m_bDragFullWindow) { int dx = m_ptDragEnd.x - m_ptDragStart.x; int cxy = max(0, m_nItemWidth + dx); SetItemWidth(m_nDraggingItem, cxy); } } else { // cancel and restore the original width if(m_bDragFullWindow)SetItemWidth(m_nDraggingItem, m_nItemWidth); } m_nDraggingItem = -1; ReleaseCapture(); } void CHeaderCtrlExt::DrawDragDivider() { CWnd* pParent = GetParent(); CDC* pDC = pParent->GetDCEx(NULL, DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); int nROP2 = pDC->SetROP2(R2_NOT); CPen pen; pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); CPen* pPenOld = pDC->SelectObject(&pen); CRect rc; pParent->GetWindowRect(&rc); ScreenToClient(&rc); CRect rcItem; GetItemRect(m_nDraggingItem, &rcItem); int dx = m_ptDragMove.x - m_ptDragStart.x; int x = max(rcItem.left, rcItem.right + dx); pDC->MoveTo(x, rc.top); pDC->LineTo(x, rc.bottom); pDC->SelectObject(pPenOld); pDC->SetROP2(nROP2); pParent->ReleaseDC(pDC); } int CHeaderCtrlExt::ItemFromPoint(CPoint point) { for(int i = 0;i < GetItemCount();++i) { CRect rc; GetItemRect(i, &rc); if(rc.PtInRect(point))return i; } return -1; } void CHeaderCtrlExt::ResetItemWidth(int nIndex) { CItemData* pData = (CItemData*)GetItemData(nIndex); if(pData)SetItemWidth(nIndex, pData->m_nWidth); }